package useraddress

import (
	"context"
	"encoding/json"
	"strings"
	"time"

	"mall/common/modelx"
	"mall/common/resultx"
	"mall/service/user/model"
	"mall/service/user/rpc/internal/svc"
	"mall/service/user/rpc/types/user"

	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type UpdateUserAddressLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdateUserAddressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateUserAddressLogic {
	return &UpdateUserAddressLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *UpdateUserAddressLogic) UpdateUserAddress(in *user.UserAddressInfo) (*user.BaseResp, error) {
	if in.Id == nil || *in.Id == 0 || in.UserId == nil || *in.UserId == 0 {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	if in.Consignee != nil && len(strings.TrimSpace(*in.Consignee)) == 0 {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_CONSIGNEE_REQUIRED, "")
	}

	if in.Mobile != nil && len(strings.TrimSpace(*in.Mobile)) == 0 {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_CONSIGNEE_REQUIRED, "")
	}

	if in.DetailedAddress != nil && len(strings.TrimSpace(*in.DetailedAddress)) == 0 {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_ADDRESS_REQUIRED, "")
	}

	//省  市  区  街道
	var province string
	var city string
	var district string
	var street string
	//地区代码
	var regionCodes []string
	var geographicJson null.JSON
	if len(in.Geographic) > 0 {
		for idx, v := range in.Geographic {
			if v.Label != nil && len(strings.TrimSpace(*v.Label)) > 0 && v.Value != nil && len(strings.TrimSpace(*v.Value)) > 0 {
				if idx == 0 {
					province = strings.TrimSpace(*v.Label)
					regionCodes = append(regionCodes, strings.TrimSpace(*v.Value))
				} else if idx == 1 {
					city = strings.TrimSpace(*v.Label)
					regionCodes = append(regionCodes, strings.TrimSpace(*v.Value))
				} else if idx == 2 {
					district = strings.TrimSpace(*v.Label)
					regionCodes = append(regionCodes, strings.TrimSpace(*v.Value))
				} else if idx == 3 {
					street = strings.TrimSpace(*v.Label)
					regionCodes = append(regionCodes, strings.TrimSpace(*v.Value))
				}
			}
		}

		if len(regionCodes) < 3 {
			return nil, resultx.StatusError(resultx.USER_ADDRESS_GEOGRAPHIC_INVALID, "")
		}

		geographic, err := json.Marshal(in.Geographic)
		if err != nil {
			return nil, resultx.StatusError(resultx.USER_ADDRESS_GEOGRAPHIC_INVALID, "")
		}

		geographicJson = null.JSONFrom(geographic)
	}

	//查询后修改
	address, err := l.svcCtx.UserAddress.FindOneNoCache(l.ctx, nil, *in.Id)
	if err != nil {
		return nil, err
	}

	if address.UserID != *in.UserId {
		return nil, resultx.StatusError(resultx.USER_ADDRESS_ID_INVALID, "")
	}

	var isDefaultIds []uint64
	tx, err := l.svcCtx.DB.BeginTx(l.ctx, nil)
	if err != nil {
		return nil, err
	}

	if in.Label != nil && len(strings.TrimSpace(*in.Label)) > 0 {
		address.Label = strings.TrimSpace(*in.Label)
	}
	if in.Consignee != nil {
		address.Consignee = strings.TrimSpace(*in.Consignee)
	}
	if in.Mobile != nil {
		address.Mobile = strings.TrimSpace(*in.Mobile)
	}

	if len(regionCodes) >= 3 {
		address.Province = province
		address.City = city
		address.District = district
		address.Street = street
		address.RegionCode = strings.Join(regionCodes, ",")
		address.Geographic = geographicJson
	}

	if in.DetailedAddress != nil {
		address.DetailedAddress = strings.TrimSpace(*in.DetailedAddress)
	}
	if in.PostalCode != nil && len(strings.TrimSpace(*in.PostalCode)) > 0 {
		address.PostalCode = strings.TrimSpace(*in.PostalCode)
	}
	if in.IsDefault != nil {
		address.IsDefault = uint8(*in.IsDefault)

		if address.IsDefault > 0 {
			filterMap := make(map[string]map[string][]any)
			filterMap[model.UserAddressColumns.UserID] = map[string][]any{
				"equalTo": {*in.UserId},
			}
			filterMap[model.UserAddressColumns.IsDefault] = map[string][]any{
				"equalTo": {true},
			}
			res, _, err := l.svcCtx.UserAddress.GetList(l.ctx, model.M{}, -1, filterMap)
			if err != nil {
				return nil, err
			}

			for _, v := range res {
				isDefaultIds = append(isDefaultIds, v.UserAddressID)
			}
		}
	}
	if in.Status != nil {
		address.Status = uint8(*in.Status)
	}
	now := time.Now()
	address.UpdatedAt = now
	if in.LastUsedAt != nil {
		if localTime, err := modelx.ParseLocalTime(*in.LastUsedAt); err == nil {
			address.LastUsedAt = null.TimeFrom(localTime)
		}
	}
	err = l.svcCtx.UserAddress.Update(l.ctx, tx, address)
	if err != nil {
		tx.Rollback()
		return nil, err
	}

	if len(isDefaultIds) > 0 {
		err = l.svcCtx.UserAddress.UpdateBatch(l.ctx, tx, isDefaultIds, model.M{
			model.UserAddressColumns.IsDefault: false,
			model.UserAddressColumns.UpdatedAt: now,
		})
		if err != nil {
			tx.Rollback()
			return nil, err
		}
	}

	tx.Commit()

	return &user.BaseResp{}, nil
}
